package com.zhtools.wx.bean;

import com.zhtools.wx.exception.WXPayException;
import com.zhtools.wx.utils.WXPayUtil;
import com.zhtools.wx.utils.WXUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhanghao
 * 微信公众号支付请求统一下单参数封装
 */
public class WXPayOrder implements Serializable {
    private static final long serialVersionUID = 6918277238879560890L;
    private static final Logger LOGGER = LoggerFactory.getLogger(WXPayOrder.class);
    private static final String TRADE_TYPE = "JSAPI";
    private static final String EMPTY_STRING = "";
    private static final String PATTERN = "#";

    private static final String PRODUCTDESC_EMPTY_EXCEPTION = "支付单商品描述不能为空";
    private static final String OPENID_EMPTY_EXCEPTION = "支付单openId不能为空";
    private static final String ORDERCODE_EMPTY_EXCEPTION = "支付单号不能为空";
    private static final String IP_EMPTY_EXCEPTION = "支付单ip不能为空";
    private static final String TOTALFEE_EXCEPTION = "支付单金额不能为空或者金额必须大于0元";
    private static final String TRANSFORM_EXCEPTION = "转换微信支付接口请求报文异常";

    private String productDesc;
    private String openId;
    private String orderCode;
    private String ip;
    private BigDecimal totalFee;
    private String goodsTag;

    public String getProductDesc() {
        return productDesc;
    }

    public void setProductDesc(String productDesc) {
        this.productDesc = productDesc;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public String getOrderCode() {
        return orderCode;
    }

    public void setOrderCode(String orderCode) {
        this.orderCode = orderCode;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public BigDecimal getTotalFee() {
        return totalFee;
    }

    public void setTotalFee(BigDecimal totalFee) {
        this.totalFee = totalFee;
    }

    public String getGoodsTag() {
        return goodsTag;
    }

    public void setGoodsTag(String goodsTag) {
        this.goodsTag = goodsTag;
    }

    /**
     * 参数验证
     */
    public void verifyParams() throws WXPayException {
        if (StringUtils.isEmpty(productDesc)) {
            throw new WXPayException(PRODUCTDESC_EMPTY_EXCEPTION);
        }
        if (StringUtils.isEmpty(openId)) {
            throw new WXPayException(OPENID_EMPTY_EXCEPTION);
        }
        if (StringUtils.isEmpty(orderCode)) {
            throw new WXPayException(ORDERCODE_EMPTY_EXCEPTION);
        }
        if (StringUtils.isEmpty(ip)) {
            throw new WXPayException(IP_EMPTY_EXCEPTION);
        }
        if (totalFee == null || totalFee.doubleValue() <= 0) {
            throw new WXPayException(TOTALFEE_EXCEPTION);
        }
    }

    /**
     * 转成接口报文需要的XML格式字符串
     */
    public String toXml(String appId, String mchId, String notifyUrl, String signKey) throws WXPayException {
        //参数验证
        verifyParams();
        String nonce_str = WXUtil.generateNonceStr();
        DecimalFormat decimalFormat = new DecimalFormat(PATTERN);

        Map<String, String> params = new HashMap<>();
        params.put("appid", appId);
        params.put("body", productDesc);
        params.put("mch_id", mchId);
        params.put("nonce_str", nonce_str);
        params.put("notify_url", notifyUrl);
        params.put("openid", openId);
        params.put("out_trade_no", orderCode);
        params.put("spbill_create_ip", ip);
        params.put("total_fee", decimalFormat.format(totalFee));
        params.put("trade_type", TRADE_TYPE);
        params.put("goods_tag", goodsTag);

        String requestXml = EMPTY_STRING;
        try {
            requestXml = WXPayUtil.generateSignedXml(params, signKey);
        } catch (Exception e) {
            throw new WXPayException(TRANSFORM_EXCEPTION, e);
        }
        return requestXml;
    }
}
